The
Twice-Cooked Method Macromedia Flash has
always been able to generate an HTML page that contains
Macromedia Flash movies. Initially, it was a tool called
AfterShock. Since the release of Macromedia Flash 4,
authors could export HTML pages with embedded movies
from within the Macromedia Flash authoring environment.
Macromedia Flash produces markup that's the de facto
standard you'll find in 99 percent of sites that use
Macromedia Flash movies: <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com
/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0"
width="400" height="300" id="movie" align="">
<param name="movie" value="movie.swf">
<embed src="movie.swf" quality="high" width="400"
height="300" name="movie" align="" type="application/x-shockwave-flash"
plug inspage="http://www.macromedia.com/go/getflashplayer">
</object>
As you can see, the included code is a bit of a
monster. Two main tags embed the movie and require that
you declare every value twice. Microsoft Internet
Explorer (IE) and similar browsers primarily use one
tag; browsers that consider themselves friends of
Netscape use the other. I call this "The Twice Cooked
Method." Here's what I mean.
The <embed>
tag is not part of the XHTML specification and it will
prevent your page from validating. Netscape and similar
browsers use it for displaying Macromedia Flash movies.
Parameters are passed within the tag as name/value
attribute pairs.
Netscape created the <embed> tag as a way to embed
plug-ins and players in web pages. The <embed> tag is not part of
the XHTML specification, and although some browsers
other than Netscape do support it, it's not compliant
with standards, so you shouldn't use it.
Bye bye <embed> . . . it's been
swell.
Meanwhile, although the <object> tag is part
of the XHTML specification, it's badly implemented here.
IE-style browsers use it to start an instance of
Macromedia Flash Player and load the specified movie.
The <param> tag
is its counterpart, passing any number of parameters to
the player once it starts.
Without the <embed> tag, you're left with
the <object> tag,
which is why it's prudent to understand the <object> tag's capabilities
fully. The great news is that just about every popular
browser supports the <object> tag in one way or
another.
The <object>
tag has no required attributes, but there are many you
can use. Below are the more interesting ones, along with
edited highlights from the W3C specification:
classid (URI) |
This attribute
specifies the location of an object's
implementation through a URI. You may use it with
or as an alternative to the data attribute (see below),
depending on the type of object involved. |
codebase (URI) |
This attribute specifies the base
path used to resolve relative URIs specified by
the classid ,
data , and
archive
attributes. When absent, its default value is the
base URI of the current document. |
data (URI) |
This specifies the location of
the object's data or, more generally, a serialized
form of an object that can be used to recreate
it. |
type (content-type) |
This attribute specifies the
content type for the data specified by data . |
codetype (content-type) |
This attribute specifies the
content type of expected data when downloading the
object that classid
specifies. |
Other attributes allow references to archived
versions, cause text to display while loading (we can do
this in Macromedia Flash already), and so on. There are
also the common attributes, such as width , height , id , and class . The attributes listed above,
however, are particularly relevant when it comes to
embedding Macromedia Flash movies.
Another useful thing I learned is that an <object> tag can contain child
elements that you can then use as an alternative
if the browser doesn't have the capability
of displaying the object itself. In fact,
this is how the undesirable nested <embed>
tag works in Netscape browsers. I discuss
this more later.
Cleaning
up the Markup Armed with a more thorough
understanding of the markup, I wanted to test my code in
various browsers. My first step was to try the
Macromedia markup by stripping the <embed> tag and cleaning it
up for XHTML:
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com
/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0"
width="400" height="300" />
<param name="movie" value="movie.swf" />
</object>
Unfortunately, this simply doesn't work outside
IE-style browsers. After a little research and some
searching on Google, I discovered that the GUID I used
in the classid
attribute was specific to the browser's ActiveX
configuration. In fact, it caused Netscape 7 and Mozilla
to ignore the object entirely. The classid attribute does, however,
perform an important function: It tells the browser
which player to use. We can't simply get rid of it
without replacing its functionality with something
else.
Fortunately, the Macromedia Flash Player default
configuration responds to content with an application/x-shockwave-flash MIME
type. This is great because the type attribute allows you to
specify a content type. Therefore, instead of using
this: classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
You would use this: type="application/x-shockwave-flash"
This change still doesn't permit movies to play in
Netscape browsers on their own, however. So I tried
something else.
Next, examine the codebase attribute, which contains
a path to a copy of the Macromedia Flash plug-in on the
servers at Macromedia. Using the attribute this way is
incorrect, however, because any paths within it are
supposed to be within the same domainit's a security
feature.
In many browsers (primarily Internet Explorer), the
codebase attribute
performs another function. The path contains a string on
the end (#version=6,0,0,0 ) that specifies
which plug-in version the server should deliver. If the
version declared is later than the version currently
installed on the user's machine, the browser will ask
the user whether or not to update the player. One
disadvantage of this tactic is that the codebase attribute also stops the
movie from playing in Netscape and Mozilla when used in
this way. That's not ideal so I won't use it. I discuss
a workaround for this lost functionality more at the end
of this article. By eliminating the codebase attribute, we've
simplified our markup: <object type="application/x-shockwave-flash"
width="400" height="300" />
<param name="movie" value="movie.swf" />
</object>
If you try this code, however, it still won't load a
movie in Netscape.
Having gotten this far, I worried that there was no
way to use valid markup to deliver Macromedia Flash in
Netscape browsers. Every time I asked this question, all
of my resources confirmed that it was impossible.
So I did what I always do: I started trying crazy
things.
Making Some Progress When I tried
the data attribute, I
was ecstatic because movies suddenly played in Netscape
and Mozilla. When I flipped back to IE, I saw that
movies played there, too: <object type="application/x-shockwave-flash" data="movie.swf"
width="400" height="300">
<param name="movie" value="movie.swf" />
</object>
After testing with larger movies, however, I noticed
something was amiss. Although every other browser
processed the request and played the movie correctly,
Internet Explorer running on Windows was not
streamingit waited for the entire movie to download
before playing it. While this is acceptable for small
movies, for anything larger this lack of streaming is
unacceptable. I concluded that valid markup for
Macromedia Flash movies was possible but only when
Microsoft had fixed their problem in Internet Explorer
for Windows.
The Satay Method A few days later
I discussed this issue with Jeffrey Zeldman, explaining
how I came close to a solution but hadn't quite found
it. He was interested that I managed to come close,
having experienced this same problem on recent projects.
I started thinking and, while driving home that evening,
the solution hit me.
As I said, the only problem with the code I created
was that Internet Explorer for Windows didn't really
stream the movie; it waited for the whole movie to
download before playing it. So what if I created a very
small container movie, inside of which the first frame
loaded the real movie?
I tested it and it worked! It's a bit of a hack
solution, but a valid and justifiable hack in my
opinion. One benefit is that you don't have to create a
separate container movie for each "real" movieone smart
container can work with any Macromedia Flash movie, as
long as it has the same proportions.
No matter whether your movie is made from beef,
chicken, or pork, you still need to skewer it and dip it
in the sauce to make it work. We call this "The Satay
Method." Create the container
movie. I created a new Macromedia
Flash movie and put the following ActionScript on Frame
1 right in the root of the movie:
_root.loadMovie(_root.path,0);
This instructs Macromedia Flash Player to load a
movie, whose name is in the variable path on the root, into Level 0 of the current movie. All
you need to do is ensure that a variable called
path holds the name of
the movie you want to load.
Macromedia Flash makes this easy because Macromedia
Flash Player loads any name/value pairs that are passed
to a movie on a query string to the movie's root. This
is useful for many different applications, but in this
case it means that you call the movie like this: c.swf?path=movie.swf
The container movie is c.swf . I pass it a variable called
path with a value of
movie.swf . This means
that the ActionScript, when evaluated, would be: _root.loadMovie("movie.swf",0);
You can modify the behavior of the container movie to
do whatever you likeas long as you keep it small. You
can use GET and POST to pass variables through the
container if you need to, for example. This method,
however, only works well if the container movie is just
a few kilobytes. Finalize the
markup. Now all you need to do is
drop a lot of attributes, add some sparkling new ones,
and tidy it all up:
<object type="application/x-shockwave-flash" data="c.swf?path=movie.swf"
width="400" height="300">
<param name="movie" value="c.swf?path=movie.swf" />
</object>
So there it ismeaner, leaner, and altogether better
for the environment. But what about that functionality
we lost when we eliminated the codebase attribute? The main
problem with getting rid of the codebase attribute is that in
Internet Explorer and similar browsers it causes the
browser to prompt the user to update their Macromedia
Flash plug-in if it's outdated. This is a really useful
feature, as it may be the only way that most
ordinary web users update their players.
My workaround is simple: Just include one sacrificial
movie at the front of your site that has the codebase attribute. This must be a
movie with no purpose within the sitejust a 1K empty
movie that causes the browser to prompt the user when
they have an old version of the plug-in. While this is
not the cleanest approach, it's pragmaticand you won't
lose any friends over it. Embedding Elements in the <object>
Tag Remember the <object> tag behavior I
mentioned earlier, where the browser tries to parse a
child element if it can't work with the object itself?
This behavior has its benefits.
If you look at the source code of the home page at
macromedia.com, you will see that they serve up an
alternative image if the user can't view Macromedia
Flash movies. They are detecting the Macromedia Flash
Player with JavaScript and then using JavaScript to
dynamically write out HTML based on the detection. This
is ugly, ugly, ugly.
Here's how I would do it: <object type="application/x-shockwave-flash" data="c.swf?path=movie.swf"
width="400" height="300">
<param name="movie" value="c.swf?path=movie.swf" />
<img src="noflash.gif" width="200" height="100" alt="" />
</object>
If the browser cannot play objects with a MIME type
of application/x-shockwave-flash , it
will simply default to the next child element and
display it (such as a simple image element, which would
be acceptable for most users). If that fails, you can
simply display text.
I've written this article knowing that it's simply my
own findings and, thus, a work in progress. Consider
that this article is similar to a scientific theory:
What I state today is only proven until someone
disproves it. You can follow the progress of this technique
on my site, where I'll continue to research and document
my findings.
This article first appeared in A List
Apart magazine. |